package com.dd.keel.core.framework.proxy;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dd.keel.core.common.flea.ConnectException;
import com.dd.keel.core.common.flea.SendException;
import com.dd.keel.core.common.utils.ByteUtil;

/**
 * Proxy connection
 * 
 * @author Kevin.XU
 *
 */
public class ProxyConn {

	final static private Logger LOGGER = LoggerFactory
			.getLogger(ProxyConn.class);

	private String host = null;
	private int port = 0;

	private Socket client = null;
	private OutputStream out = null;
	private InputStream in = null;

	public ProxyConn(String host, int port) {
		this.host = host;
		this.port = port;
	}
	
	/**
	 * Connect to remote server
	 * @return
	 */
	public boolean connect() {
		if (client == null) {
			boolean flag = false;
			try {
				LOGGER.info("begin connect to {}:{} ", host, port);
				client = new Socket();
				client.setKeepAlive(true);
				client.setReceiveBufferSize(57 * 1024);
				client.setSendBufferSize(57 * 1024);
				client.setTcpNoDelay(true);
				client.setReuseAddress(true);
				client.setSoLinger(true, 30);
				SocketAddress remoteAddr = new InetSocketAddress(host,
						port);
				client.connect(remoteAddr, 3 * 1000);
				out = client.getOutputStream();
				in = client.getInputStream();
				if (client.isConnected()){
					client.setSoTimeout(3 * 1000);
					flag = true;
					LOGGER.info("connect to {}:{} successfully!", host, port);
				}else{
					LOGGER.error("connect to {}:{} failed!", host, port);
				}
					
			} catch (IOException ex) {
				LOGGER.error(ex.getMessage(), ex);
			} catch (Exception ex) {
				LOGGER.error(ex.getMessage(), ex);
			}
			return flag;
		} else {
			return true;
		}
	}

	/**
	 * Disconnect to remote server
	 */
	public void disconnect() {
		LOGGER.info( "close to {}:{}", host, port );
		try{
			if(out!=null) out.close();
		}catch(Exception ex){
			LOGGER.error( ex.getMessage(), ex );
		}
		try{
			if(in!=null) in.close();
		}catch(Exception ex){
			LOGGER.error( ex.getMessage(), ex );
		}
		try{
			if(client!=null) client.close();
		}catch(Exception ex){
			LOGGER.error( ex.getMessage(), ex );
		}
		client = null;
	}

	/**
	 * Reconnect to remote server
	 * @return
	 */
	public boolean reconnect() {
		disconnect();
		return connect();
	}

	public void send(byte[] buffer,int off,int len) throws IOException
	{
		out.write(buffer, off, len);
		out.flush();
	}
	
	public void receive(byte[] buffer,int len) throws IOException
	{
		int retry = 3;
		boolean canRead = false;
		while(retry-->0){
			if(available()<len){
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
				}
			}else{
				canRead = true;
				break;
			}
		}
		if(canRead){
			int ret = in.read(buffer);
			if(ret<len){
				throw new IOException("read failed");
			}
		}else{
			throw new IOException("not found enough bytes");
		}
	}
	
	public int available() throws IOException
	{
		return in.available();
	}
	
	public void consumeContent() throws IOException
	{
		if(in!=null)
		{
			if(in.available()>0) in.skip(in.available());
		}
	}
	
}
